package ln.fxspringarchetype.controller.score;

import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import ln.fxspringarchetype.controller.BaseFxController;
import ln.fxspringarchetype.dialog.score.AddScoreDialog;
import ln.fxspringarchetype.dialog.score.DeleteScoreDialog;
import ln.fxspringarchetype.dialog.score.EditScoreDialog;
import ln.fxspringarchetype.mapper.CourseMapper;
import ln.fxspringarchetype.mapper.ScoreMapper;
import ln.fxspringarchetype.mapper.StudentMapper;
import ln.fxspringarchetype.model.Score;
import ln.fxspringarchetype.util.DateUtil;
import org.apache.logging.log4j.util.Strings;
import org.controlsfx.control.Notifications;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.util.Objects;
import java.util.Optional;

@Controller
public class ScoreController extends BaseFxController {
    private final IntegerProperty pageNum = new SimpleIntegerProperty(Integer.MIN_VALUE);
    private final IntegerProperty pageSize = new SimpleIntegerProperty(Integer.MIN_VALUE);
    private final IntegerProperty pageCount = new SimpleIntegerProperty(Integer.MIN_VALUE);
    private final StringProperty keyword = new SimpleStringProperty(Strings.EMPTY);

    private final ObjectProperty<ObservableList<Score>> scoreRecords = new SimpleObjectProperty<>();

    @FXML
    private TextField searchBox;
    @FXML
    private ChoiceBox<Integer> pageSizeChoice;
    @FXML
    private TableView<Score> scoreTable;
    @FXML
    private TableColumn<Score, Integer> recordIdColumn;
    @FXML
    private TableColumn<Score, String> studentNameColumn;
    @FXML
    private TableColumn<Score, String> courseNameColumn;
    @FXML
    private TableColumn<Score, String> examDateColumn;
    @FXML
    private TableColumn<Score, Double> scoreColumn;
    @FXML
    private Pagination pagination;

    @Autowired
    private ScoreMapper scoreMapper;
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private CourseMapper courseMapper;

    @Override
    public void setCellValueFactories() {
        recordIdColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
        scoreColumn.setCellValueFactory(new PropertyValueFactory<>("score"));
        examDateColumn.setCellValueFactory(param -> {
            Score score = param.getValue();
            return new SimpleStringProperty(DateUtil.dateToDateString(score.getExamDate()));
        });
        studentNameColumn.setCellValueFactory(param -> {
            Score score = param.getValue();
            if (Objects.isNull(score) || Objects.isNull(score.getStudent())) {
                return new SimpleStringProperty(Strings.EMPTY);
            }
            return new SimpleStringProperty(score.getStudent().getName());
        });
        courseNameColumn.setCellValueFactory(param -> {
            Score score = param.getValue();
            if (Objects.isNull(score) || Objects.isNull(score.getCourse())) {
                return new SimpleStringProperty(Strings.EMPTY);
            }
            return new SimpleStringProperty(score.getCourse().getName());
        });
    }

    @Override
    public void setCellFactories() {

    }

    @Override
    public void createBindings() {
        pageNum.bind(pagination.currentPageIndexProperty());
        pageSize.bind(pageSizeChoice.valueProperty());
        keyword.bind(searchBox.textProperty());
        //根据页码、记录数、查询关键词自动加载学生信息
        scoreRecords.bind(
                Bindings.createObjectBinding(
                        () -> {
                            int pNum = pageNum.getValue();
                            int pSize = pageSize.getValue();
                            String kw = keyword.getValue();
                            if (pNum < 0 || pSize <= 0) {
                                return FXCollections.emptyObservableList();
                            }
                            if (Strings.isEmpty(kw)) {
                                return FXCollections.observableList(scoreMapper.findPage(pNum, pSize));
                            } else {
                                return FXCollections.observableList(scoreMapper.findPageByStudentName(kw, pNum, pSize));
                            }
                        }, pageNum, pageSize, keyword));
        scoreTable.itemsProperty().bind(scoreRecords);

        pageCount.bind(Bindings.createIntegerBinding(
                () -> {
                    int pNum = pageNum.getValue();
                    int pSize = pageSize.getValue();
                    String kw = keyword.getValue();
                    if (pNum < 0 || pSize <= 0) {
                        return 0;
                    }
                    if (Strings.isEmpty(kw)) {
                        return scoreMapper.pageCount(pSize);
                    } else {
                        return scoreMapper.pageCountByStudentName(kw, pSize);
                    }
                }, pageNum, pageSize, keyword));

        pagination.pageCountProperty().bind(pageCount);
    }

    @Override
    public void initLayout() {

    }

    @Override
    public void loadData() {
        pagination.setCurrentPageIndex(0);
        pageSizeChoice.getSelectionModel().selectFirst();
    }

    private void reload() {
        pagination.setCurrentPageIndex(-1);
    }

    @FXML
    private void addScore(ActionEvent actionEvent) {
        AddScoreDialog addScoreDialog = new AddScoreDialog();
        //更新对话框内下拉列表的数据
        addScoreDialog.loadListData(studentMapper, courseMapper);
        Optional<Score> scoreToAdd = addScoreDialog.showAndWait();
        if (scoreToAdd.isPresent()) {
            int inserted = scoreMapper.insert(scoreToAdd.get());
            Notifications notifications;
            if (inserted > 0) {
                notifications = showPrompt("新增选课信息成功", String.format("选课 %s 的信息已经成功添加。",
                        scoreToAdd.get().getStudent().getName()));
                notifications.showInformation();
            } else {
                notifications = showPrompt("新增选课信息失败", String.format("选课 %s 的信息未能成功添加。",
                        scoreToAdd.get().getStudent().getName()));
                notifications.showError();
            }
            reload();
        }
    }

    @FXML
    private void deleteScore(ActionEvent actionEvent) {
        Score score = scoreTable.getSelectionModel().getSelectedItem();
        if (Objects.isNull(score)) {
            showPrompt("没有选择选课信息", "请选择一条选课信息！");
            return;
        }
        DeleteScoreDialog deleteScoreDialog = new DeleteScoreDialog();
        deleteScoreDialog.loadScore(score);
        Optional<Score> scoreToDelete = deleteScoreDialog.showAndWait();
        if (scoreToDelete.isPresent()) {
            int deleted = scoreMapper.delete(score.getId());
            Notifications notifications;
            if (deleted > 0) {
                notifications = showPrompt("删除选课信息成功", String.format("选课 %s 的信息已经成功删除。",
                        score.getStudent().getName()));
                notifications.showInformation();
            } else {
                notifications = showPrompt("删除选课信息失败", String.format("选课 %s 的信息没有成功删除。",
                        score.getStudent().getName()));
                notifications.showError();
            }
            reload();
        }
    }

    @FXML
    private void editScore(ActionEvent actionEvent) {
        Score score = scoreTable.getSelectionModel().getSelectedItem();
        if (Objects.isNull(score)) {
            showPrompt("没有选择选课信息", "请选择一条选课信息！");
            return;
        }
        EditScoreDialog editScoreDialog = new EditScoreDialog();
        editScoreDialog.loadListData(studentMapper, courseMapper);
        editScoreDialog.loadScore(score);
        Optional<Score> scoreToEdit = editScoreDialog.showAndWait();
        if (scoreToEdit.isPresent()) {
            int edited = scoreMapper.update(scoreToEdit.get());
            Notifications notifications;
            if (edited > 0) {
                notifications = showPrompt("修改选课信息成功", String.format("选课 %s 的信息已经成功修改。",
                        scoreToEdit.get().getStudent().getName()));
                notifications.showInformation();
            } else {
                notifications = showPrompt("修改选课信息失败", String.format("选课 %s 的信息未能成功修改。",
                        scoreToEdit.get().getStudent().getName()));
                notifications.showError();
            }
            reload();
        }
    }
}
